# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-08-05 23:27
# File     : auth.py
# Project  : codebuddy_craft
# Desc     :
# backend/schemas/auth.py
"""
认证数据模式定义 🔐

定义认证相关的请求和响应数据结构
"""

from pydantic import BaseModel, Field, EmailStr, validator
from typing import Optional, Dict, Any
from datetime import datetime


class LoginRequest(BaseModel):
    """登录请求模型 🔑"""
    username: str = Field(..., min_length=3, max_length=50, description="用户名或邮箱")
    password: str = Field(..., min_length=6, description="密码")

    @validator('username')
    def validate_username(cls, v):
        """验证用户名"""
        return v.strip().lower()


class RegisterRequest(BaseModel):
    """注册请求模型 📝"""
    username: str = Field(..., min_length=3, max_length=50, description="用户名")
    email: EmailStr = Field(..., description="邮箱地址")
    password: str = Field(..., min_length=8, description="密码")
    full_name: Optional[str] = Field(None, max_length=100, description="全名")

    @validator('username')
    def validate_username(cls, v):
        """验证用户名"""
        import re
        if not re.match(r'^[a-zA-Z0-9_-]+$', v):
            raise ValueError('用户名只能包含字母、数字、下划线和连字符')
        return v.strip().lower()

    @validator('full_name')
    def validate_full_name(cls, v):
        """验证全名"""
        if v:
            return v.strip()
        return v


class TokenResponse(BaseModel):
    """令牌响应模型 🎫"""
    access_token: str = Field(..., description="访问令牌")
    refresh_token: str = Field(..., description="刷新令牌")
    token_type: str = Field(default="bearer", description="令牌类型")
    expires_in: int = Field(..., description="过期时间(秒)")


class RefreshTokenRequest(BaseModel):
    """刷新令牌请求模型 🔄"""
    refresh_token: str = Field(..., description="刷新令牌")


class ChangePasswordRequest(BaseModel):
    """修改密码请求模型 🔐"""
    current_password: str = Field(..., description="当前密码")
    new_password: str = Field(..., min_length=8, description="新密码")

    @validator('new_password')
    def validate_new_password(cls, v, values):
        """验证新密码"""
        current_password = values.get('current_password')
        if current_password and v == current_password:
            raise ValueError('新密码不能与当前密码相同')
        return v


class UserResponse(BaseModel):
    """用户响应模型 👤"""
    id: str = Field(..., description="用户ID")
    username: str = Field(..., description="用户名")
    email: str = Field(..., description="邮箱地址")
    full_name: Optional[str] = Field(None, description="全名")
    avatar_url: Optional[str] = Field(None, description="头像URL")
    is_active: bool = Field(..., description="是否激活")
    is_verified: bool = Field(..., description="是否已验证")
    preferences: Dict[str, Any] = Field(default_factory=dict, description="用户偏好")
    created_at: Optional[datetime] = Field(None, description="创建时间")
    last_login_at: Optional[datetime] = Field(None, description="最后登录时间")

    class Config:
        from_attributes = True
        json_encoders = {
            datetime: lambda v: v.isoformat() if v else None
        }


class PasswordResetRequest(BaseModel):
    """密码重置请求模型 🔄"""
    email: EmailStr = Field(..., description="邮箱地址")


class PasswordResetConfirm(BaseModel):
    """密码重置确认模型 ✅"""
    token: str = Field(..., description="重置令牌")
    new_password: str = Field(..., min_length=8, description="新密码")


class EmailVerificationRequest(BaseModel):
    """邮箱验证请求模型 📧"""
    token: str = Field(..., description="验证令牌")
